package com.atguigu.daijia.payment.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.common.http.HttpUtils;
import com.atguigu.daijia.common.constant.MqConst;
import com.atguigu.daijia.common.execption.GuiguException;
import com.atguigu.daijia.common.result.ResultCodeEnum;
import com.atguigu.daijia.common.service.RabbitService;
import com.atguigu.daijia.common.util.*;
import com.atguigu.daijia.driver.client.DriverAccountFeignClient;
import com.atguigu.daijia.model.entity.order.OrderInfo;
import com.atguigu.daijia.model.entity.payment.PaymentInfo;
import com.atguigu.daijia.model.enums.TradeType;
import com.atguigu.daijia.model.form.driver.TransferForm;
import com.atguigu.daijia.model.form.payment.PaymentInfoForm;
import com.atguigu.daijia.model.vo.order.OrderRewardVo;
import com.atguigu.daijia.model.vo.payment.WxPrepayVo;
import com.atguigu.daijia.order.client.OrderInfoFeignClient;
import com.atguigu.daijia.order.service.OrderInfoService;
import com.atguigu.daijia.payment.config.WeixinpayProperties;
import com.atguigu.daijia.payment.config.WxPayConfiguration;
import com.atguigu.daijia.payment.controller.WxPayController;
import com.atguigu.daijia.payment.mapper.PaymentInfoMapper;
import com.atguigu.daijia.payment.service.WxPayService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
//import io.seata.spring.annotation.GlobalTransactional;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;

import org.apache.http.HttpResponse;

import org.apache.http.ParseException;
import org.jdom.JDOMException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.invoke.LambdaConversionException;
import java.math.BigDecimal;
import java.security.MessageDigest;
import java.util.*;

@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {
    private final static Logger logger=
            LoggerFactory.getLogger(WxPayController.class);

    @Autowired
    private PaymentInfoMapper paymentInfoMapper;

    @Autowired
    private WeixinpayProperties weixinpayProperties;

    @Autowired
    private RabbitService rabbitService;
    @Autowired
    private OrderInfoService orderInfoService;
    @Autowired
    private OrderInfoFeignClient orderInfoFeignClient;

    @Autowired
    private DriverAccountFeignClient driverAccountFeignClient;
//    @Autowired
//    private WxPayConfiguration wxPayConfiguration;

    @Override
    public Map createWxPayment(PaymentInfoForm paymentInfoForm) {
        try {
            //1 添加支付记录到支付表里面
            //判断：如果表存在订单支付记录，不需要添加
            LambdaQueryWrapper<PaymentInfo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(PaymentInfo::getOrderNo, paymentInfoForm.getOrderNo());
            PaymentInfo paymentInfo = paymentInfoMapper.selectOne(wrapper);
            if (paymentInfo == null) {
                paymentInfo = new PaymentInfo();
                BeanUtils.copyProperties(paymentInfoForm, paymentInfo);
                paymentInfo.setPaymentStatus(0);
                paymentInfoMapper.insert(paymentInfo);
            }
//----------------------------------------------------------------------------------------------------
//            //2 创建微信支付使用对象
//            JsapiServiceExtension service =
//                    new JsapiServiceExtension.Builder().config(rsaAutoCertificateConfig).build();
//
//            //3 创建request对象，封装微信支付需要参数
//            PrepayRequest request = new PrepayRequest();
//            Amount amount = new Amount();
//
//            //amount.setTotal(paymentInfoForm.getAmount().multiply(new BigDecimal(100)).intValue());
//            amount.setTotal(1);
//            request.setAmount(amount);
//            request.setAppid("wx201dd3f1a0a12f22");
//            request.setMchid("1572670171");
//            //string[1,127]
//            String description = paymentInfo.getContent();
//            if(description.length() > 127) {
//                description = description.substring(0, 127);
//            }
//            request.setDescription(description);
//
//            request.setNotifyUrl( "http://www.yourdomain.com/compere/api/notify");
//
//            request.setOutTradeNo(paymentInfo.getOrderNo());
//
//            //获取用户信息
//            Payer payer = new Payer();
//            payer.setOpenid(paymentInfoForm.getCustomerOpenId());
//            request.setPayer(payer);
//
//            //是否指定分账，不指定不能分账
//            SettleInfo settleInfo = new SettleInfo();
//            settleInfo.setProfitSharing(true);
//            request.setSettleInfo(settleInfo);
//
//            //4 调用微信支付使用对象里面方法实现微信支付调用
//            PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
//
//            //5 根据返回结果，封装到WxPrepayVo里面
//            WxPrepayVo wxPrepayVo = new WxPrepayVo();
//            BeanUtils.copyProperties(response,wxPrepayVo);
//            wxPrepayVo.setTimeStamp(response.getTimeStamp());
//            return wxPrepayVo;
            Map<String, Object> map = new HashMap();
            map.put("appid", "wx201dd3f1a0a12f22");
            map.put("mch_id", "1572670171");
            map.put("nonce_str", StringUtil.getRandomString(32));
            map.put("body","jianpumallorder");

            // 订单号
            map.put("out_trade_no", paymentInfoForm.getOrderNo());
            // 商品价格
            map.put("total_fee",1);

            map.put("spbill_create_ip","127.0.0.1");
            map.put("notify_url","https://3dwuvybje99q.ngrok.xiaomiqiu123.top/payment/wxPay/notify");
            map.put("trade_type","JSAPI");
            map.put("openid",paymentInfo.getCustomerOpenId());
            map.put("sign",getSign(map));
            //参数转成xml
            String xml= XmlUtil.genXml(map);
            System.out.println("xml="+ xml);
            HttpResponse httpResponse = HttpClientUtil.sendXMLDataByPost("https://api.mch.weixin.qq.com/pay/unifiedorder",xml);
            String httpEntityContent = HttpClientUtil.getHttpEntityContent(httpResponse);
            System.out.println(httpEntityContent);
            //转成map
            Map resultMap = XmlUtil.doXMLParse(httpEntityContent);
//            JsapiServiceExtension service =
//                    new JsapiServiceExtension.Builder().config(rsaAutoCertificateConfig).build();
//            PrepayRequest request = new PrepayRequest();
//            Amount amount = new Amount();
//
////            //amount.setTotal(paymentInfoForm.getAmount().multiply(new BigDecimal(100)).intValue());
//           amount.setTotal(1);
//            request.setAmount(amount);
//            request.setAppid("wx201dd3f1a0a12f22");
//            request.setMchid("1572670171");
//            //string[1,127]
//            String description = paymentInfo.getContent();
//            if(description.length() > 127) {
//                description = description.substring(0, 127);
//            }
//            request.setDescription(description);
//
//            request.setNotifyUrl( "http://www.yourdomain.com/compere/api/notify");
//
//            request.setOutTradeNo(paymentInfo.getOrderNo());
//
//
//            Payer payer = new Payer();
//            payer.setOpenid(paymentInfoForm.getCustomerOpenId());
//            request.setPayer(payer);
//
//            //是否指定分账，不指定不能分账
//            SettleInfo settleInfo = new SettleInfo();
//            settleInfo.setProfitSharing(true);
//            request.setSettleInfo(settleInfo);
//
//            //4 调用微信支付使用对象里面方法实现微信支付调用
//            PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
//
//            //5 根据返回结果，封装到WxPrepayVo里面
//            WxPrepayVo wxPrepayVo = new WxPrepayVo();
//            BeanUtils.copyProperties(response,wxPrepayVo);
//            wxPrepayVo.setTimeStamp(response.getTimeStamp());
            WxPrepayVo wxPrepayVo = new WxPrepayVo();
            if(resultMap.get("return_code").equals("SUCCESS"))
            {Map<String,Object> payMap = new HashMap();
                payMap.put("appId",resultMap.get("appid"));
                payMap.put("timeStamp",System.currentTimeMillis()/1000 + "");
                payMap.put("nonceStr",StringUtil.getRandomString(32));
                payMap.put("package", "prepay_id=" + resultMap.get("prepay_id"));
                payMap.put("signType","MD5");
                payMap.put("paySign",getSign(payMap));
                payMap.put("orderNo",paymentInfoForm.getOrderNo());
                System.out.println(payMap);

                return payMap;

            }
            return null;


        } catch (Exception e) {
            e.printStackTrace();
            throw new GuiguException(ResultCodeEnum.DATA_ERROR);
        }


    }
    private String string2MD5(String str) {
        if (str == null || str.length() == 0) {
            return null;
        }
        char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                'a', 'b', 'c', 'd', 'e', 'f'};
        try {
            MessageDigest mdTemp = MessageDigest.getInstance("MD5");
            mdTemp.update(str.getBytes("UTF-8"));
            byte[] md = mdTemp.digest();
            int j = md.length;
            char buf[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
                buf[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(buf).toUpperCase();
        } catch (Exception e) {
            return null;
        }
    }
    private String getSign(Map<String, Object> map) {
        StringBuffer sb = new StringBuffer();
        String[] keyArr = (String[]) map.keySet().toArray(new
                String[map.keySet().size()]);//获取map中的key转为array
        Arrays.sort(keyArr);//对array排序
        for (int i = 0, size = keyArr.length; i < size; ++i) {
            if ("sign".equals(keyArr[i])) {
                continue;
            }
            sb.append(keyArr[i] + "=" + map.get(keyArr[i]) + "&");
        }
        sb.append("key=" +"kt946iningCZKTIsBest012345678902");
        String sign = string2MD5(sb.toString());
        System.out.println("sign=" + sign);
        return sign;
    }


    //查询支付状态
    @Override
    public Boolean queryPayStatus(String orderNo) {
//        //1 创建微信操作对象
//        JsapiServiceExtension service =
//                new JsapiServiceExtension.Builder().config(rsaAutoCertificateConfig).build();
//
//        //2 封装查询支付状态需要参数
//        QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
//        queryRequest.setMchid("1572670171");
//        queryRequest.setOutTradeNo(orderNo);
//
//        //3 调用微信操作对象里面方法实现查询操作
//        Transaction transaction = service.queryOrderByOutTradeNo(queryRequest);
//
//        //4 查询返回结果，根据结果判断
//        if (transaction != null
//                && transaction.getTradeState() == Transaction.TradeStateEnum.SUCCESS) {
//            //5 如果支付成功，调用其他方法实现支付后处理逻辑
//            this.handlePayment(transaction);
//
//            return true;
//        }

//HttpClientUtil httpClientUtil=HttpClientUtil.getInstance();
//String httpResponse=httpClientUtil.sendHttpsGet("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{orderNo}?mchid=1572670171");
//        System.out.println("----------------"+httpResponse);
        return false;
    }


    //微信支付成功后，进行的回调
    @Override
    public void wxnotify(HttpServletRequest request) throws IOException, JDOMException {
        //1.回调通知的验签与解密
        //从request头信息获取参数
        //HTTP 头 Wechatpay-Signature
        // HTTP 头 Wechatpay-Nonce
        //HTTP 头 Wechatpay-Timestamp
        //HTTP 头 Wechatpay-Serial
        //HTTP 头 Wechatpay-Signature-Type
        //HTTP 请求体 body。切记使用原始报文，不要用 JSON 对象序列化后的字符串，避免验签的 body 和原文不一致。
//        String wechatPaySerial = request.getHeader("Wechatpay-Serial");
//        String nonce = request.getHeader("Wechatpay-Nonce");
//        String timestamp = request.getHeader("Wechatpay-Timestamp");
//        String signature = request.getHeader("Wechatpay-Signature");
//        String requestBody = RequestUtils.readData(request);
////
//        //2.构造 RequestParam
//        RequestParam requestParam = new RequestParam.Builder()
//                .serialNumber(wechatPaySerial)
//                .nonce(nonce)
//                .signature(signature)
//                .timestamp(timestamp)
//                .body(requestBody)
//                .build();
//
//        //3.初始化 NotificationParser
//        NotificationParser parser = new NotificationParser();
//        //4.以支付通知回调为例，验签、解密并转换成 Transaction
//        Transaction transaction = parser.parse(requestParam, Transaction.class);
//
//        if (null != transaction && transaction.getTradeState() == Transaction.TradeStateEnum.SUCCESS) {
//            //5.处理支付业务
//            this.handlePayment(transaction);
//        }

        InputStream inputStream;
        StringBuffer sb=new StringBuffer();
        inputStream=request.getInputStream();
        String s;
        BufferedReader in=new BufferedReader(new
                InputStreamReader(inputStream,"UTF-8"));
        while (((s=in.readLine())!=null)){
            sb.append(s);

        }
        in.close();
        inputStream.close();

// 解析xml成map
        Map<String,String> m=new HashMap<>();
        m= XmlUtil.doXMLParse(sb.toString());
// 过滤空 设置TreeMap
        SortedMap<Object,Object> packageParams=new TreeMap<>();
        Iterator<String> it = m.keySet().iterator();
        while(it.hasNext()){
            String parameter = it.next();
            String parameterValue = m.get(parameter);
            String v="";
            if(parameterValue!=null){
                v=parameterValue.trim();
            }
            packageParams.put(parameter,v);
        }

// 微信支付的API秘钥
        String key="kt946iningCZKTIsBest012345678902";
        String out_trade_no= (String) packageParams.get("out_trade_no");
        if(isTenpaySign("UTF-8",packageParams,key)){
            logger.info("验证签名通过");
            if("SUCCESS".equals(packageParams.get("result_code"))){

                PaymentInfo order = paymentInfoMapper.selectOne(new QueryWrapper<PaymentInfo>
                        ().eq("order_no", out_trade_no));
                if(order!=null && order.getPaymentStatus()==0){
                    //1 更新支付记录，状态修改为 已经支付
                    //订单编号
                    String orderNo = order.getOrderNo();
                    //根据订单编号查询支付记录
                    LambdaQueryWrapper<PaymentInfo> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(PaymentInfo::getOrderNo, orderNo);
                    PaymentInfo paymentInfo = paymentInfoMapper.selectOne(wrapper);
                    //如果已经支付，不需要更新
                    if (paymentInfo.getPaymentStatus() == 1) {
                        return;
                    }
                    //
                    paymentInfo.setPaymentStatus(1);
                    paymentInfo.setOrderNo(order.getOrderNo());
                    paymentInfo.setTransactionId(orderNo);
                    paymentInfo.setCallbackTime(new Date());
                    paymentInfo.setCallbackContent(JSON.toJSONString(""));
                    paymentInfoMapper.updateById(paymentInfo);
                    this.handleOrder(orderNo);

                    //2 发送端：发送mq消息，传递 订单编号
                    //  接收端：获取订单编号，完成后续处理
                    rabbitService.sendMessage(MqConst.EXCHANGE_ORDER,
                            MqConst.ROUTING_PAY_SUCCESS,
                            orderNo);
                    logger.info(out_trade_no+"：微信服务器异步修改订单状态成功！");
                }
            }
        }
    }



    //支付成功后续处理
//    @GlobalTransactional
    @Override
    public void handleOrder(String orderNo) {
        //1 远程调用：更新订单状态：已经支付
        orderInfoFeignClient.updateOrderPayStatus(orderNo);

        //2 远程调用：获取系统奖励，打入到司机账户
        OrderRewardVo orderRewardVo = orderInfoFeignClient.getOrderRewardFee(orderNo).getData();
        if (orderRewardVo != null && orderRewardVo.getRewardFee().doubleValue() > 0) {
            TransferForm transferForm = new TransferForm();
            transferForm.setTradeNo(orderNo);
            transferForm.setTradeType(TradeType.REWARD.getType());
            transferForm.setContent(TradeType.REWARD.getContent());
            transferForm.setAmount(orderRewardVo.getRewardFee());
            transferForm.setDriverId(orderRewardVo.getDriverId());
            //3
            driverAccountFeignClient.transfer(transferForm);
        }



    }

    //如果支付成功，调用其他方法实现支付后处理逻辑
    public void handlePayment(Transaction transaction) {

        //1 更新支付记录，状态修改为 已经支付
        //订单编号
        String orderNo = transaction.getOutTradeNo();
        //根据订单编号查询支付记录
        LambdaQueryWrapper<PaymentInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PaymentInfo::getOrderNo, orderNo);
        PaymentInfo paymentInfo = paymentInfoMapper.selectOne(wrapper);
        //如果已经支付，不需要更新
        if (paymentInfo.getPaymentStatus() == 1) {
            return;
        }
        //
        paymentInfo.setPaymentStatus(1);
        paymentInfo.setOrderNo(transaction.getOutTradeNo());
        paymentInfo.setTransactionId(transaction.getTransactionId());
        paymentInfo.setCallbackTime(new Date());
        paymentInfo.setCallbackContent(JSON.toJSONString(transaction));
        paymentInfoMapper.updateById(paymentInfo);

        //2 发送端：发送mq消息，传递 订单编号
        //  接收端：获取订单编号，完成后续处理
        rabbitService.sendMessage(MqConst.EXCHANGE_ORDER,
                MqConst.ROUTING_PAY_SUCCESS,
                orderNo);
    }
    public static boolean isTenpaySign(String characterEncoding,
                                       SortedMap<Object, Object> packageParams, String API_KEY) {
        StringBuffer sb = new StringBuffer();
        Set es = packageParams.entrySet();
        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String k = (String)entry.getKey();
            String v = (String)entry.getValue();
            if(!"sign".equals(k) && null != v && !"".equals(v)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + API_KEY);
//算出摘要
        String mysign = MD5Util.MD5Encode(sb.toString(),
                characterEncoding).toLowerCase();
        String tenpaySign = ((String)packageParams.get("sign")).toLowerCase();
        return tenpaySign.equals(mysign);
    }

}
